﻿using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using ShevaEngine.Core.Interfaces;

namespace ShevaEngine.Core.Modules.Materials
{
    /// <summary>
    /// Animated texture.
    /// </summary>
    public class AnimatedTexture2D : Texture2D, IUpdateAble
    {
        /// <summary>Configuration.</summary>
        private AnimatedTexture2DConfiguration Config;
        /// <summary>Base texture.</summary>
        private Texture2D BaseTexture;
        /// <summary>Copy rectangle.</summary>
        private Rectangle CopyRectangle;
        /// <summary>Buffer.</summary>
        private Byte[] Buffer;
        /// <summary>Start time.</summary>
        private DateTime StartTime;
        /// <summary>Actual frame.</summary>
        private Int32 ActualFrame;
        /// <summary>Actual real frame.</summary>
        private Int32 ActualRealFrame;
        /// <summary>Actual real loop count.</summary>
        private Int32 ActualRealLoopCount;

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="configuration"></param>
        public AnimatedTexture2D(AnimatedTexture2DConfiguration configuration)
            : base(ShevaEngine.Instance.GraphicsDevice, configuration.Width, configuration.Height)
        {
            this.Config = configuration;
            this.BaseTexture = ShevaEngine.Instance.Content.Load<Texture2D>("Textures\\" + configuration.TextureName);
            this.CopyRectangle = new Rectangle(0, 0, this.Width, this.Height);
            this.Buffer = new byte[this.Width * this.Height * 4];

            this.StartTime = DateTime.Now;

            this.SetFrame(0);
        }

        /// <summary>
        /// Method sets frame.
        /// </summary>
        /// <param name="id"></param>
        private void SetFrame(int id)
        {
            this.ActualFrame = id;

            this.CopyRectangle.X = id * this.Width;

            this.BaseTexture.GetData<byte>(0, this.CopyRectangle, this.Buffer, 0, this.Buffer.Length);

            this.SetData<byte>(this.Buffer);
        }

        /// <summary>
        /// Method Update().
        /// </summary>
        /// <param name="time"></param>
        public void Update(GameTime time)
        {
            this.ActualRealFrame = (int)Math.Floor((DateTime.Now - this.StartTime).TotalSeconds / this.Config.StepTime);

            this.ActualRealLoopCount = this.ActualRealFrame / this.Config.FramesCount;

            if (this.ActualRealLoopCount < this.Config.LoopCount)
            {
                this.ActualRealFrame = this.ActualRealFrame % this.Config.FramesCount;

                if (this.ActualFrame != this.ActualRealFrame)
                    this.SetFrame(this.ActualRealFrame);
            }
            else
                if (this.ActualFrame != this.Config.FrameAfterEnd)
                    this.SetFrame(this.Config.FrameAfterEnd);
        }

        /// <summary>
        /// Reset.
        /// </summary>
        public void Reset()
        {
            this.StartTime = DateTime.Now;
        }
    }
}
